<template>
  <div class="app-container">
    <!-- 表格 -->
    <vxe-grid ref="xGridDom" v-bind="xGridOpt">
      <!-- 左侧按钮列表 -->
      <template #toolbar-btns>
        <vxe-button status="primary" icon="vxe-icon-add" @click="crudStore.onShowModal()">新增漏洞</vxe-button>
        <el-dropdown style="margin-left: 10px;margin-right: 10px">
          <vxe-button status="danger" icon="vxe-icon-arrow-down">批量操作</vxe-button>
          <template #dropdown>
            <el-dropdown-menu style="width: 110px">
              <el-dropdown-item @click="crudStore.batchOpt(1)">
                <span>置为已修复</span>
              </el-dropdown-item>
              <el-dropdown-item @click="crudStore.batchOpt(2)">
                <span>置为待修复</span>
              </el-dropdown-item>
              <el-dropdown-item @click="crudStore.batchImport()">
                <span>批量导入</span>
              </el-dropdown-item>
              <el-dropdown-item @click="crudStore.batchOpt(3)">
                <span>批量删除</span>
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>


        <vxe-button status="success" icon="vxe-icon-download" @click="downloadTemplate()">下载导入模板</vxe-button>
      </template>


      <!--      展开行的内容-->
      <template #expand-content="{ row }">
        <div style="margin: 20px">
          <el-row>
            <el-col :span="2">
              <el-tag>发现版本</el-tag>
            </el-col>
            <el-col :span="2">{{ row.discoverVersion }}</el-col>

            <el-col :span="2">
              <el-tag>反馈者</el-tag>
            </el-col>
            <el-col :span="2">{{ row.feedbackName }}</el-col>

            <template v-if="row.status === 1">
              <template v-if="row.fixVersion != ''">
                <el-col :span="2">
                  <el-tag>修复版本</el-tag>
                </el-col>
                <el-col :span="2">{{ row.fixVersion }}</el-col>
              </template>

              <template v-if="row.FixerName != ''">
                <el-col :span="2">
                  <el-tag>修复者</el-tag>
                </el-col>
                <el-col :span="2">{{ row.FixerName }}</el-col>
              </template>
            </template>

          </el-row>
          <template v-if="row.tags != ''">
            <el-divider/>
            <el-row>
              <el-col :span="2">
                <el-tag>漏洞标签</el-tag>
              </el-col>
              <el-col :span="22">
                <Tag :tags="row.tags" :readonly="true"></Tag>
              </el-col>
            </el-row>

          </template>

          <el-divider/>
          <el-row>
            <el-col :span="2">
              <el-tag>漏洞描述</el-tag>
            </el-col>
            <el-col :span="18">
              <div>
                <span class="text">{{ row.bugDesc }}</span>
              </div>

            </el-col>
          </el-row>
          <el-divider/>
          <el-row>
            <el-col :span="2">
              <el-tag>验证信息</el-tag>
            </el-col>
            <el-col :span="20">
              <span class="text">{{ row.verifyInfo }}</span>
            </el-col>
          </el-row>
          <el-divider/>
          <el-row>
            <el-col :span="2">
              <el-tag>修复建议</el-tag>
            </el-col>
            <el-col :span="20">
              <span class="text">{{ row.fixSuggest }}</span>
            </el-col>
          </el-row>
          <template v-if="row.comment != ''">
            <el-divider/>
            <el-row>
              <el-col :span="2">
                <el-tag>备注</el-tag>
              </el-col>
              <el-col :span="20">
                <span class="text">{{ row.comment }}</span>
              </el-col>
            </el-row>
          </template>
        </div>
      </template>

      <!--  状态 -->
      <template #row-status="{ row }">
        <el-switch
          v-model="row.status"
          inline-prompt
          :active-value=1
          :inactive-value=2
          active-text="已修复"
          inactive-text="待修复"
          @change="switchStatus(row)"
        />
      </template>

      <!-- 操作 -->
      <template #row-operate="{ row }">
        <el-tooltip
          class="box-item"
          effect="dark"
          content="下载附件"
          placement="top-end">
          <el-button
            :disabled="row.attachmentID === 0"
            link type="primary"
            icon="Download"
            @click="downloadFile(row.attachmentID)"
          />
        </el-tooltip>
        <el-divider direction="vertical"/>
        <el-tooltip class="box-item" effect="dark" content="编辑" placement="top-end">
          <el-button link icon="Edit" type="primary" @click="crudStore.onShowModal(row)"/>
        </el-tooltip>
        <el-divider direction="vertical"/>
        <el-tooltip class="box-item" effect="dark" content="删除" placement="top-end">
          <el-button link icon="Delete" type="danger" @click="crudStore.onDelete(row)"/>
        </el-tooltip>
      </template>


    </vxe-grid>
    <!-- 弹窗 -->
    <vxe-modal ref="xModalDom" v-bind="xModalOpt">
      <!-- 表单 -->
      <vxe-form ref="xFormDom" v-bind="xFormOpt" @keydown="handleInputKeydown">
        <template #batchImport>
          <el-upload
            ref="upload1"
            action="#"
            :limit="1"
            :on-exceed="handleExceed"
            :auto-upload="false"
            accept=".xlsx"
            :on-change="handleChange"
            :http-request="customUpload"
            style="width: 100%;"
          >
            <template #trigger>
              <el-button size="default">选择导入文件</el-button>
            </template>
          </el-upload>
        </template>
        <template #tag>
          <Tag/>
        </template>
      </vxe-form>
    </vxe-modal>

    <!--    切换漏洞状态-->
    <el-dialog
      v-model="mpDialogVisible"
      title="修复漏洞"
      :before-close="mpHandleClose"
      :close-on-click-modal="false"
      :show-close="false"
      width="350px"
    >
      <el-form
        ref="mpFormRef"
        :model="mpFormData"
        :rules="mpFormRules"
        label-width="100px"
        label-position="left"
        style="width: 95%; margin-top: 15px"
      >
        <el-form-item label="修复版本" prop="version">
          <el-input
            v-model.trim="mpFormData.version"
            autocomplete="off"
            clearable
          />
        </el-form-item>
        <el-form-item label="修复者" prop="fixer">
          <el-select
            v-model="mpFormData.fixer"
            class="m-2"
            placeholder="请选择"
            clearable
            filterable
            style="width: 100%;">
            <el-option
              v-for="item in peopleOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
      <span class="dialog-footer">
          <el-button @click="mpCloseDialog">取消</el-button>
          <el-button type="primary" @click="mpOperateAction(mpFormRef)">确认</el-button>
      </span>
      </template>
    </el-dialog>

    <!--    批量导入漏洞结果反馈-->
    <el-dialog
      v-model="resDialogVisible"
      :before-close="mpHandleClose"
      :close-on-click-modal="false"
      :show-close="false"
      width="500px"
    >
      <el-row>
        <el-col :span="24">
          <el-result icon="success" title="漏洞导入完成！"/>
        </el-col>
        <el-col :offset="2" :span="6">
          <el-statistic title="导入总数" :value="resultData.total"/>
        </el-col>
        <el-col :offset="2" :span="6">
          <el-statistic title="成功数量" :value="resultData.success"/>
        </el-col>
        <el-col :offset="2" :span="6">
          <el-statistic title="失败数量" :value="resultData.fail"/>
        </el-col>
        <el-col :offset="16" :span="8" style="margin-top: 40px">
          <el-button type="primary" @click="copyResult()">复制导入结果详情</el-button>
        </el-col>
      </el-row>
    </el-dialog>
  </div>
</template>

<script lang="ts" setup>
import {computed, nextTick, reactive, ref, Ref, watch} from "vue"
import {
  type ElMessageBoxOptions,
  ElMessageBox,
  ElMessage,
  ElInput,
  FormInstance,
  FormRules,
  UploadProps, UploadRawFile, genFileId, UploadInstance, UploadRequestOptions
} from "element-plus"
import BugLevelColumnSolts from "./tsx/BugLevelColumnSolts";
import {copyData, CopyToClipboard, formatDateTime, trimValue} from "@/utils/index"
import Tag from "@/components/Tag/index.vue"
import {downloadFile} from "@/utils/customer"


import {
  type VxeGridInstance,
  type VxeGridProps,
  type VxeModalInstance,
  type VxeModalProps,
  type VxeFormInstance,
  type VxeFormProps,
  type VxeGridPropTypes,
  type VxeFormDefines
} from "vxe-table"

import {
  CustomerTableData, selectOption
} from "@/api/customer"
import {batchDeleteBugApi, batchImportBug, RowMeta} from "@/api/customer/bugfix"
import {useRouter} from "vue-router";
import {getAllCustomer, getAllPeople} from "@/utils/customer";
import {appOption, bugLevelOption, bugStatusOption, tooltipInfo} from "@/views/customer/bugfix/dict";
import {addBugApi, deleteBugApi, getBugApi, switchBugStatusApi, updateBugApi} from "@/api/customer/bugfix";
import {usePublicCompStore} from "@/store/modules/publicComponents";
import {storeToRefs} from "pinia";
import {getCustomerFileApi} from "@/api/customer/files";


defineOptions({
  name: "Bugfix"
})


const router = useRouter()

const PublicComStore = usePublicCompStore()
const {tags} = storeToRefs(PublicComStore)

const customerOptions = ref<selectOption[]>([])
const peopleOptions = ref<selectOption[]>([])
const attachmentOption = ref<selectOption[]>([])
getAllCustomer().then((Options) => {
  if (Options) {
    customerOptions.value = Options || []
  }
})

getAllPeople().then((Options) => {
  if (Options) {
    peopleOptions.value = Options || []
  }
})

// 下载导入模板
const downloadTemplate = () => {
  // 创建一个隐藏的 <a> 标签来触发下载
  const link = document.createElement('a');
  link.href = "https://ss.bscstorage.com/bspackage/filestore/orchsym_ORM/public/%E5%AF%BC%E5%85%A5%E6%BC%8F%E6%B4%9E%E6%A8%A1%E6%9D%BF.xlsx"
  link.style.display = 'none'
  document.body.appendChild(link)
  // 触发点击事件并自动下载
  link.click()
  // 移除 <a> 标签
  document.body.removeChild(link)
}

// 获取客户文件列表选项
const getFileOptions = async (customerId) => {
  if (crudStore.isFetchingFileOptions) {
    return; // 如果正在获取数据，不重复触发
  }
  crudStore.isFetchingFileOptions = true
  xFormOpt.loading = true
  try {
    const res = await getCustomerFileApi({customerId: customerId})
    attachmentOption.value = res.data.list.map((item) => {
      return {
        value: item.id,
        label: item.name
      }
    })

    if (attachmentOption.value.length === 0) {
      ElMessage({
        type: "warning",
        message: "没有查询到当前客户相关的文件！"
      })
    }
  } catch (error) {
    console.log(error)
  } finally {
    crudStore.isFetchingFileOptions = false
    xFormOpt.loading = false;
  }
}

const handleInputKeydown = (event) => {
  if (event.keyCode === 13) {
    event.preventDefault(); // 阻止默认的回车事件行为
  }
}

//#region import result
const resDialogVisible = ref<boolean>(false)

const resultData = reactive({
  total: 0,
  success: 0,
  fail: 0,
  allRes: ""
})
const copyResult = () => {
  const jsonString = JSON.stringify(resultData.allRes, null, 2); // 格式化 JSON 字符串，第二个参数表示缩进两个空格
  CopyToClipboard(jsonString)
  // 复制完后关闭对话框
  resDialogVisible.value = false
  // 触发一次查询便于加载最新的数据
  crudStore.commitQuery()
}
//#endregio


//#region el-upload
const upload1 = ref<UploadInstance>()
// 覆盖前一个文件
const handleExceed: UploadProps['onExceed'] = (files) => {
  upload1.value!.clearFiles()
  const file = files[0] as UploadRawFile
  file.uid = genFileId()
  upload1.value!.handleStart(file)
}

// 限制文件的类型
const handleChange: UploadProps['onChange'] = (file, uploadFiles) => {
  if (file.status === "ready") {
    const f = uploadFiles[0]
    let suffix = f.name.substring(f.name.lastIndexOf(".") + 1);

    const extension = suffix === "xlsx";
    if (!extension) {
      ElMessage.error("上传文件只能是.xlsx格式!")
      uploadFiles.shift()          // 移除第一个元素
    }
    return extension;
  }
}

// 自定义上传文件的请求
const customUpload = (options: UploadRequestOptions) => {
  return new Promise((resolve, reject) => {
    const formData = new FormData();
    formData.append(options.filename || 'file', options.file);
    formData.append('customerID', xFormOpt.data.customerID)
    formData.append('envVersion', xFormOpt.data.envVersion)
    formData.append('attachmentID', xFormOpt.data.attachmentID)
    formData.append('feedback', xFormOpt.data.feedback)
    formData.append('comment', xFormOpt.data.comment)
    formData.append('tags', tags.value.join(","))

    batchImportBug(formData).then((res) => {
      const d = res.data
      resultData.success = d.success.total
      resultData.fail = d.fail.total
      resultData.total = d.success.total + d.fail.total
      resultData.allRes = d
      resDialogVisible.value = true
      resolve(res)
    }).catch((error) => {
      reject(error)
    })
    upload1.value!.clearFiles()
  })
}

//#endregion


//#region statusDialog
const mpDialogVisible = ref<boolean>(false)
const mpFormRef = ref<FormInstance>()

const mpFormData = reactive({
  id: 0,
  ids: "",
  newStatus: 0,
  version: "",
  fixer: "",
})

const mpInitForm = () => {
  mpFormData.id = 0
  mpFormData.ids = ""
  mpFormData.newStatus = 0
  mpFormData.version = ""
  mpFormData.fixer = ""
}

const mpCloseDialog = () => {
  mpFormRef.value?.resetFields()
  mpInitForm()
  mpDialogVisible.value = false
}

const mpFormRules: FormRules = reactive({
  version: [{required: true, trigger: "blur", message: "版本号不能为空"}],
  fixer: [{required: true, trigger: "blur", message: "修复者不能为空"}],
})

const mpHandleClose = (done: Function) => {
  mpInitForm()
  done()
}
const switchStatus = (row: RowMeta) => {
  mpFormData.id = row.id
  mpFormData.newStatus = row.status
  if (row.status === 2) {
    const s = async () => {
      await switchBugStatusApi({
        id: mpFormData.id,
        ids: mpFormData.ids,
        status: row.status,
      }).then((res) => {
        if (res.code === 0) {
          ElMessage({type: "success", message: res.msg})
          crudStore.commitQuery()
        }
      })
        .catch(() => {
        })
    }
    s()
    mpCloseDialog()
  } else {
    mpDialogVisible.value = true
  }
  // 这里先不能修改这个值
  row.status = row.status === 1 ? 2 : 1
}

const mpOperateAction = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.validate(async (valid) => {
    if (valid) {
      await switchBugStatusApi({
        id: mpFormData.id,
        ids: mpFormData.ids,
        status: mpFormData.newStatus,
        version: mpFormData.version,
        fixer: mpFormData.fixer,
      })
        .then((res) => {
          if (res.code === 0) {
            ElMessage({type: "success", message: res.msg})
            mpCloseDialog()
            crudStore.commitQuery()
          }
        })
        .catch(() => {
          mpCloseDialog()
        })
    }
  })
}
//#endregion

//#region vxe-grid
const xGridDom = ref<VxeGridInstance>()


const xGridOpt: VxeGridProps = reactive({
  loading: true,
  autoResize: true,
  /** 分页配置项 */
  pagerConfig: {
    align: "right"
  },
  /** 表单配置项 */
  formConfig: {
    items: [
      {
        field: "name",
        itemRender: {
          name: "$input",
          props: {placeholder: "客户名称", clearable: true}
        }
      },
      {
        field: "cve",
        itemRender: {
          name: "$input",
          props: {placeholder: "CVE 编号", clearable: true}
        }
      },
      {
        field: "app",
        span: 3,
        itemRender: {
          name: "$select",
          props: {placeholder: "选择影响应用", clearable: true, filterable: true},
          options: appOption
        }
      },
      {
        field: "status",
        span: 3,
        itemRender: {
          name: "$select",
          props: {placeholder: "选择漏洞状态", clearable: true},
          options: bugStatusOption
        }
      },
      {
        field: "bugLevel",
        span: 3,
        itemRender: {
          name: "$select",
          props: {placeholder: "选择漏洞等级", clearable: true},
          options: bugLevelOption
        }
      },
      {
        field: "tag",
        itemRender: {
          name: "$input",
          props: {placeholder: "标签", clearable: true}
        }
      },
      {
        itemRender: {
          name: "$buttons",
          children: [
            {
              props: {type: "submit", content: "搜索", status: "primary"}
            }
          ]
        }
      }
    ]
  },
  /** 工具栏配置 */
  toolbarConfig: {
    refresh: true,
    custom: false,
    export: false,
    import: false,
    slots: {
      buttons: "toolbar-btns"
    }
  },
  /** 复选框配置 */
  checkboxConfig: {
    checkField: ""
  },
  /** 列配置 */
  columns: [
    {
      type: "checkbox",
      width: "50px"
    },
    {
      type: 'expand', // 设置列类型为展开列
      width: "50px", // 设置展开列的宽度
      title: "详情",
      slots: {content: "expand-content"}
    },
    {
      field: "id",
      title: "ID",
      width: "90px"
    },
    {
      field: "name",
      title: "客户名称",
    },
    {
      field: "envVersion",
      title: "环境版本",
      width: "100px",
      formatter: ({row}) => {
        // 数据库设置此字段是not null,所以不用做空处理
        return `release-${row.envVersion}.x`
      }
    },
    {
      field: "cve",
      title: "CVE 编号",
    },
    {
      field: "bugLevel",
      title: "漏洞等级",
      width: "80px",
      slots: BugLevelColumnSolts
    },
    {
      field: "status",
      title: "状态",
      slots: {default: "row-status"}
    },
    {
      field: "app",
      title: "影响应用",
      formatter: ({row}) => {
        switch (row.app) {
          case 1:
            return "runtime"
          case 2:
            return "core-api-java"
          case 3:
            return "crystal-java-3"
          case 4:
            return "orchsym-web-3"
          case 5:
            return "hd-cfg-api"
          case 6:
            return "keycloak"
          case 7:
            return "elasticsearch"
          case 8:
            return "kibana"
          case 9:
            return "grafana"
          case 10:
            return "nginx"
          case 11:
            return "zookeeper"
          case 12:
            return "cassandra"
          case 13:
            return "mysql"
          case 14:
            return "redis"
          case 15:
            return "keepalived"
          case 100:
            return "其他"
          default:
            return "N/A"
        }
      }
    },
    {
      field: "updatedAt",
      sortable: true,
      title: "更新时间",
      formatter: (params) => {
        return formatDateTime(params.row.updatedAt)
      }
    },
    {
      title: "操作",
      width: "250px",
      fixed: "right",
      showOverflow: false,  // 当内容过多时，是否要溢出显示
      slots: {default: "row-operate"}
    }
  ],
  /** 数据代理配置项（基于 Promise API） */
  proxyConfig: {
    /** 启用动态序号代理 */
    seq: true,
    /** 是否代理表单 */
    form: true,
    props: {
      total: "total"
    },
    ajax: {
      query: ({page, form}: VxeGridPropTypes.ProxyAjaxQueryParams) => {
        xGridOpt.loading = true
        crudStore.clearTable()
        return new Promise<any>((resolve: Function) => {
          let total = 0
          let result: RowMeta[] = []
          /** 加载数据 */
          const callback = (res: CustomerTableData) => {
            if (res && res.data) {
              const resData = res.data
              // 总数
              if (Number.isInteger(resData.total)) {
                total = resData.total
              }
              // 分页数据
              if (Array.isArray(resData.list)) {
                result = resData.list
              }
            }
            xGridOpt.loading = false
            resolve({total, result})
          }

          /** 接口需要的参数 */
          const params = {
            name: trimValue(form.name),
            cve: trimValue(form.cve),
            app: form.app || undefined,
            status: form.status || undefined,
            bugLevel: form.bugLevel || undefined,
            tag: trimValue(form.tag),
            size: page.pageSize,
            currentPage: page.currentPage
          }
          /** 调用接口 */
          getBugApi(params).then(callback).catch(callback)
        })
      }
    }
  }
})
//#endregion

//#region vxe-modal
const xModalDom = ref<VxeModalInstance>()
const xModalOpt: VxeModalProps = reactive({
  title: "",
  width: "700px",
  height: "80%",
  showClose: true,
  escClosable: true,
  maskClosable: false,
  beforeHideMethod: () => {
    xFormDom.value?.clearValidate()
    xModalOpt.height = "80%"
    crudStore.isBatchImport = false
    return Promise.resolve()
  }
})
//#endregion

//#region vxe-form
const showStatus: Ref<boolean> = computed(() => {
  // 如果是在执行批量导入，则直接返回false
  if (crudStore.isBatchImport) {
    return false
  }
  return xFormOpt.data.status === 1
})

const xFormDom = ref<VxeFormInstance>()
const xFormOpt = reactive<VxeFormProps>({
  span: 20,
  titleWidth: "30%",
  loading: false,
  /** 是否显示标题冒号 */
  titleColon: false,
  titleAlign: "right",
  /** 表单数据 */
  data: {
    id: "",
    customerID: "",
    envVersion: "",
    attachmentID: "",
    cve: "",
    bugLevel: "",
    status: 0,
    app: "",
    discoverVersion: "",
    feedback: "",
    fixVersion: "",
    fixer: "",
    bugDesc: "",
    verifyInfo: "",
    fixSuggest: "",
    comment: "",
  },
  /** 项列表 */
  items: [
    {
      field: "customerID",
      title: "客户名称",
      itemRender: {
        name: "$select",
        props: {
          placeholder: "请选择",
          options: customerOptions,
          filterable: true
        }
      }
    },
    {
      field: "envVersion",
      title: "环境版本",
      itemRender: {
        name: "$select",
        props: {
          placeholder: "请选择",
          options: [
            {label: "relase-2.x", value: 2},
            {label: "relase-3.x", value: 3},
            {label: "relase-4.x", value: 4}
          ],
          clearable: true
        }
      }
    },
    {
      field: "batchImport",
      title: "导入文件",
      slots: {default: "batchImport"},
      visibleMethod: () => crudStore.isBatchImport
    },
    {
      field: "cve",
      title: "CVE 编号",
      itemRender: {
        name: "$input",
        props: {
          placeholder: "请输入CVE编号，eg: CVE-2017-10661",
          clearable: true
        }
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "bugLevel",
      title: "漏洞等级",
      itemRender: {
        name: "$select",
        props: {
          placeholder: "请选择",
          options: bugLevelOption,
        }
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "tag",
      title: "标签",
      slots: {default: "tag"}
    },
    {
      field: "attachmentID",
      title: "关联附件",
      itemRender: {
        name: "$select",
        props: {
          placeholder: "请选择",
          options: attachmentOption,
          filterable: true,
          clearable: true
        }
      }
    },
    {
      field: "app",
      title: "影响的应用",
      itemRender: {
        name: "$select",
        props: {
          placeholder: "请选择",
          clearable: true,
          options: appOption,
          filterable: true
        }
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "status",
      title: "状态",
      itemRender: {
        name: "$radio",
        options: bugStatusOption,
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "discoverVersion",
      title: "发现版本",
      itemRender: {
        name: "$input",
        props: {
          placeholder: "请输入",
          clearable: true
        }
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "feedback",
      title: "反馈人",
      itemRender: {
        name: "$select",
        props: {
          placeholder: "请选择",
          options: peopleOptions,
          filterable: true
        }
      }
    },
    {
      field: "fixVersion",
      title: "修复版本",
      itemRender: {
        name: "$input",
        props: {
          placeholder: "请输入",
          clearable: true
        }
      },
      visibleMethod: () => showStatus.value
    },
    {
      field: "fixer",
      title: "修复人",
      itemRender: {
        name: "$select",
        props: {
          placeholder: "请选择",
          options: peopleOptions,
          filterable: true
        }
      },
      visibleMethod: () => showStatus.value
    },
    {
      field: "bugDesc",
      title: "漏洞描述",
      itemRender: {
        name: "$textarea",
        props: {
          placeholder: tooltipInfo.bugDesc,
          autosize: {minRows: 5, maxRows: 5},
          clearable: true
        }
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "verifyInfo",
      title: "验证信息",
      itemRender: {
        name: "$textarea",
        props: {
          placeholder: tooltipInfo.verifyInfo,
          autosize: {minRows: 5, maxRows: 5},
          clearable: true
        }
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "fixSuggest",
      title: "修复建议",
      itemRender: {
        name: "$textarea",
        props: {
          placeholder: tooltipInfo.fixSuggest,
          autosize: {minRows: 5, maxRows: 5},
          clearable: true
        }
      },
      visibleMethod: () => !crudStore.isBatchImport
    },
    {
      field: "comment",
      title: "备注",
      itemRender: {
        name: "$textarea",
        props: {
          placeholder: "建议填写ones工单链接以及其他重要的信息",
          autosize: {minRows: 5, maxRows: 5},
          clearable: true
        }
      }
    },
    {
      align: "right",
      itemRender: {
        name: "$buttons",
        children: [
          {props: {content: "取消"}, events: {click: () => xModalDom.value?.close()}},
          {
            props: {type: "submit", content: "确定", status: "primary"},
            events: {click: () => crudStore.onSubmitForm()}
          }
        ]
      }
    }
  ],
  /** 校验规则 */
  rules: {
    customerID: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请选择")
          }
        }
      }
    ],
    envVersion: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请选择环境版本")
          }
        }
      }
    ],
    cve: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请输入")
          }
          // 暂时关闭cve编号的合法性校验（有些漏洞没有cve编号，比如es未开启用户名认证）
          // const cveRegex = /^CVE-\d{4}-\d+$/;
          // if (!cveRegex.test(itemValue)) {
          //   return new Error("CVE 编号不合法")
          // }
        }
      }
    ],
    bugLevel: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请选择")
          }
        }
      }
    ],
    app: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请选择影响的应用")
          }
        }
      }
    ],
    status: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请选择当前状态")
          }
        }
      }
    ],
    discoverVersion: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请输入当前组件版本")
          }
        }
      }
    ],
    feedback: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请选择反馈人")
          }
        }
      }
    ],
    fixVersion: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请输入修复的版本")
          }
        }
      }
    ],
    fixer: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("请选择修复者")
          }
        }
      }
    ],
    verifyInfo: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("验证信息必填")
          }
        }
      }
    ],
    fixSuggest: [
      {
        required: true,
        validator: ({itemValue}) => {
          if (!itemValue) {
            return new Error("修复建议必填")
          }
        }
      }
    ],
  }
})
//#endregion

//#region CRUD
const crudStore = reactive({
  /** 表单类型：修改：true 新增：false */
  isUpdate: true,
  /** 是否为批量导入 */
  isBatchImport: false,
  /** 是否为批量操作 */
  isBatchOpt: false,
  /** 是否正在获取数据 */
  isFetchingFileOptions: false,
  /** 加载表格数据 */
  commitQuery: () => xGridDom.value?.commitProxy("query"),
  /** 清空表格数据 */
  clearTable: () => xGridDom.value?.reloadData([]),
  /** 触发批量导入 */
  batchImport: () => {
    crudStore.isBatchImport = true
    xModalOpt.height = "600px"
    crudStore.onShowModal()
  },
  /** 批量操作 */
  batchOpt: (action: number) => {
    let ids
    let appList
    let uniqueAppList
    // 获取当前选中的所有行数据
    const res = xGridDom.value?.getCheckboxRecords(true)
    if (res.length === 0) {
      ElMessage.error("当前未选中任何行")
      return
    } else {
      ids = res.map(item => item.id).join(',')
      appList = res.map(item => item.app)
      uniqueAppList = [...new Set(appList)]
    }
    switch (action) {
      case 1:
        // 批量置为已修复
        if (uniqueAppList.length === 1) {
          mpFormData.ids = ids
          mpFormData.newStatus = 1
          mpDialogVisible.value = true
        } else {
          ElMessage.warning("选中的列表中包含多个应用，请重新选择，单次只能修复同一个应用")
        }

        return
      case 2:
        // 批量置为待修复
        const statusList = res.map(item => item.status)
        const uniqueStatusList = [...new Set(statusList)]
        // 当uniqueStatusList有且只有一个 2（待修复）状态，则不进行任何操作
        if (uniqueStatusList.length === 1 && uniqueStatusList[0] === 2) {
          ElMessage.warning("当前选中的行均为待修复状态，不进行任何操作！")
          return
        }
        // 批量置为待修复
        const formattedStrings: string[] = [];
        if (res != undefined) {
          for (const item of res) {
            const formattedString = `ID：${item.id}，CVE编号：${item.cve}`;
            formattedStrings.push(formattedString);
          }
        }
        let tip = `确定将下列漏洞置为待修复状态？</br>${formattedStrings.join('</br>')}`


        const callback = async () => {
          await switchBugStatusApi({
            ids: ids,
            status: 2,
          }).then((res) => {
            if (res.code === 0) {
              ElMessage({type: "success", message: res.msg})
              crudStore.commitQuery()
            }
          })
            .catch(() => {
            })
        }

        const config: ElMessageBoxOptions = {
          type: "warning",
          showClose: true,
          closeOnClickModal: true,
          closeOnPressEscape: true,
          cancelButtonText: "取消",
          confirmButtonText: "确定",
          dangerouslyUseHTMLString: true
        }
        ElMessageBox.confirm(tip, "提示", config)
          .then(() => {
            callback()
          })
          .catch(() => 1)
        return
      case 3:
        // 批量删除
        crudStore.isBatchOpt = true
        crudStore.onDelete(null, res)
        return
      default:
        console.log("未匹配到批量动作.")
    }
  },
  /** 点击显示弹窗 */
  onShowModal: (row?: RowMeta) => {
    if (row) {
      crudStore.isUpdate = true
      xModalOpt.title = "编辑漏洞信息"
      // 赋值
      xFormOpt.data.id = row.id
      xFormOpt.data.envVersion = row.envVersion
      xFormOpt.data.cve = row.cve
      xFormOpt.data.bugLevel = row.bugLevel
      xFormOpt.data.status = row.status
      xFormOpt.data.app = row.app
      xFormOpt.data.discoverVersion = row.discoverVersion
      xFormOpt.data.feedback = row.feedback !== 0 ? row.feedback : ""
      xFormOpt.data.fixVersion = row.fixVersion
      xFormOpt.data.fixer = row.fixer !== 0 ? row.fixer : ""
      xFormOpt.data.bugDesc = row.bugDesc
      xFormOpt.data.verifyInfo = row.verifyInfo
      xFormOpt.data.fixSuggest = row.fixSuggest
      xFormOpt.data.comment = row.comment

      getFileOptions(row.customerID).then(() => {
        xFormOpt.data.attachmentID = row.attachmentID !== 0 ? row.attachmentID : "";
      })
      // 必须最后赋值xFormOpt.data.customerID，否则可能会导致watch先监测到它的变化
      // 如果watch先触发执行了getFileOptions，那关联附件字段的赋值会有问题
      xFormOpt.data.customerID = row.customerID

      // 恢复tag列表
      if (row.tags !== "") {
        tags.value = row.tags.split(',')
      }
    } else {
      xFormOpt.data.id = 0
      crudStore.isUpdate = false
      xModalOpt.title = crudStore.isBatchImport ? "批量导入漏洞" : "新增漏洞信息"
    }
    xModalDom.value?.open()
    nextTick(() => {
      !crudStore.isUpdate && xFormDom.value?.reset()
      !crudStore.isUpdate && tags.value.splice(0, tags.value.length)
      xFormDom.value?.clearValidate()
    })
  },
  /** 确定并保存 */
  onSubmitForm: () => {
    if (xFormOpt.loading) return
    xFormDom.value?.validate(async (errMap?: VxeFormDefines.ValidateErrorMapParams) => {
      if (errMap) return
      xFormOpt.loading = true
      const callback = (err?: any) => {
        xFormOpt.loading = false
        if (err) return
        xModalDom.value?.close()
        !crudStore.isUpdate && crudStore.afterInsert()
        crudStore.commitQuery()
      }

      try {
        // 先处理批量导入的逻辑
        if (crudStore.isBatchImport) {
          upload1.value!.submit()    // 触发 http-request绑定的方法
        } else {
          let apiFunction
          if (crudStore.isUpdate) {
            apiFunction = updateBugApi
          } else {
            apiFunction = addBugApi
          }
          const res = await apiFunction({
            id: xFormOpt.data.id,
            customerID: xFormOpt.data.customerID,
            envVersion: xFormOpt.data.envVersion,
            cve: xFormOpt.data.cve,
            bugLevel: xFormOpt.data.bugLevel,
            status: xFormOpt.data.status,
            attachmentID: xFormOpt.data.attachmentID,
            app: xFormOpt.data.app,
            discoverVersion: xFormOpt.data.discoverVersion,
            feedback: xFormOpt.data.feedback,
            fixVersion: xFormOpt.data.fixVersion,
            fixer: xFormOpt.data.fixer,
            bugDesc: xFormOpt.data.bugDesc,
            verifyInfo: xFormOpt.data.verifyInfo,
            fixSuggest: xFormOpt.data.fixSuggest,
            comment: xFormOpt.data.comment,
            tags: tags.value.join(",")
          })
          ElMessage({type: "success", message: res.msg})
        }

      } catch (error) {
        console.log(error)
      } finally {
        callback()
      }
    })
  },

  /** 新增后是否跳入最后一页 */
  afterInsert: () => {
    const pager: VxeGridPropTypes.ProxyAjaxQueryPageParams | undefined = xGridDom.value?.getProxyInfo()?.pager
    if (pager) {
      const currTotal: number = pager.currentPage * pager.pageSize
      if (currTotal === pager.total) {
        ++pager.currentPage
      }
    }
  },
  /** 删除 */
  onDelete: (row: RowMeta | null, batchData: any[] | undefined) => {
    let tip
    if (crudStore.isBatchOpt) {
      const formattedStrings: string[] = [];
      if (batchData != undefined) {
        for (const item of batchData) {
          const formattedString = `ID：${item.id}，CVE编号：${item.cve}`;
          formattedStrings.push(formattedString);
        }
      }
      tip = `确定删除下列漏洞？</br>${formattedStrings.join('</br>')}`
    } else {
      tip = `确定 <strong style="color:red;">删除</strong> 漏洞 <strong style="color:#409eff;">${row.cve}</strong> ？`
    }


    const config: ElMessageBoxOptions = {
      type: "warning",
      showClose: true,
      closeOnClickModal: true,
      closeOnPressEscape: true,
      cancelButtonText: "取消",
      confirmButtonText: "确定",
      dangerouslyUseHTMLString: true
    }
    ElMessageBox.confirm(tip, "提示", config)
      .then(() => {
        if (crudStore.isBatchOpt) {
          if (batchData != undefined) {
            const ids = batchData.map(item => item.id).join(',')
            batchDeleteBugApi({ids: ids})
              .then(() => {
                ElMessage.success("删除成功")
                crudStore.afterDelete()
                crudStore.commitQuery()
              })
              .catch(() => 1)
          }
        } else {
          deleteBugApi(row.id)
            .then(() => {
              ElMessage.success("删除成功")
              crudStore.afterDelete()
              crudStore.commitQuery()
            })
            .catch(() => 1)
        }
      })
      .catch(() => 1)
  },
  /** 删除后是否返回上一页 */
  afterDelete: () => {
    const tableData: RowMeta[] = xGridDom.value!.getData()
    const pager: VxeGridPropTypes.ProxyAjaxQueryPageParams | undefined = xGridDom.value?.getProxyInfo()?.pager
    if (pager && pager.currentPage > 1 && tableData.length === 1) {
      --pager.currentPage
    }
  }
})
//#endregion

// 监听formData.customerID的变化，以便获取对应的环境列表
watch(
  () => xFormOpt.data.customerID,
  (newValue) => {
    // 客户id变了，需要先清空当前选择的附件
    xFormOpt.data.attachmentID = ""
    // 获取客户的文件列表
    if (newValue !== undefined) {
      getFileOptions(newValue)
    }
  }
)
</script>

<style lang="scss" scoped>
.expand-wrapper {
  padding: 10px;
}

.text {
  white-space: pre-wrap;
}
</style>
